package event

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/unitedrhino/protocol-wumei/service/pwumeisvr/internal/svc"
	"gitee.com/unitedrhino/share/def"
	"gitee.com/unitedrhino/things/share/devices"
	"gitee.com/unitedrhino/things/share/domain/deviceMsg"
	"gitee.com/unitedrhino/things/share/domain/deviceMsg/msgThing"
	"gitee.com/unitedrhino/things/share/domain/schema"
	"github.com/spf13/cast"
	"github.com/zeromicro/go-zero/core/logx"
	"strings"
	"time"
)

type DeviceUp struct {
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewDeviceUp(ctx context.Context, svcCtx *svc.ServiceContext) *DeviceUp {
	return &DeviceUp{
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

type PostInfo struct {
	Rssi            *int           `json:"rssi"`
	Longitude       string         `json:"longitude"`
	Latitude        string         `json:"latitude"`
	FirmwareVersion string         `json:"firmwareVersion"`
	CardNumber      *string        `json:"cardNumber"`
	MobileOperator  int64          `json:"mobileOperator"`
	Summary         map[string]any `json:"summary"`
}

type NtpReq struct {
	DeviceSendTime int64 `json:"deviceSendTime,string"`
	ServerSendTime int64 `json:"serverSendTime,string"`
	ServerRecvTime int64 `json:"serverRecvTime,string"`
}

func (d *DeviceUp) Handle(ctx context.Context, topic string, payload []byte) error {
	d.Info(topic, string(payload))
	topics := strings.Split(topic, "/")
	if topics[0] == "" {
		topics = topics[1:]
	}
	productID := topics[0]
	switch topics[len(topics)-2] {
	case "ntp":
		req := NtpReq{}
		err := json.Unmarshal(payload, &req)
		if err != nil {
			return err
		}
		req.ServerRecvTime = time.Now().UnixMilli()
		req.ServerSendTime = time.Now().UnixMilli()
		payload, err := json.Marshal(req)
		if err != nil {
			return err
		}
		err = d.svcCtx.Protocol.PublishToDev(ctx, fmt.Sprintf("/%s/%s/ntp/get", topics[0], topics[1]), payload)
		if err != nil {
			return err
		}
	case "info":
		req := PostInfo{}
		err := json.Unmarshal(payload, &req)
		if err != nil {
			return err
		}
		newReq := msgThing.Req{
			CommonMsg: deviceMsg.CommonMsg{
				Method:    deviceMsg.ReportInfo,
				MsgToken:  devices.GenMsgToken(ctx, d.svcCtx.NodeID),
				Timestamp: time.Now().UnixMilli(),
				Sys:       &deviceMsg.SysConfig{NoAsk: true},
			},
			Params: map[string]any{
				"version":        req.FirmwareVersion,
				"mobileOperator": req.MobileOperator,
			},
		}
		if req.CardNumber != nil {
			newReq.Params["iccid"] = req.CardNumber
		}
		if req.Rssi != nil {
			newReq.Params["rssi"] = req.Rssi
		}
		if req.Latitude != "" || req.Longitude != "" {
			newReq.Params["position"] = def.Point{
				CoordinateSystem: def.CoordinateSystemBaidu, //物美的是百度坐标系
				Longitude:        cast.ToFloat64(req.Longitude),
				Latitude:         cast.ToFloat64(req.Latitude),
			}
		}
		payload, _ := json.Marshal(newReq)
		err = d.svcCtx.Protocol.DevPubMsg(ctx, &devices.DevPublish{
			Topic:      topic,
			Timestamp:  time.Now().UnixMilli(),
			ProductID:  productID,
			DeviceName: topics[1],
			Handle:     devices.Thing,
			Type:       msgThing.TypeProperty,
			Payload:    payload,
		})
		return err
	case "property", "function":
		var req []Body
		err := json.Unmarshal(payload, &req)
		if err != nil {
			return err
		}
		model, err := d.svcCtx.Protocol.SchemaCache.GetData(ctx, devices.Core{ProductID: productID, DeviceName: topics[1]})
		if err != nil {
			return err
		}
		propertyReq := msgThing.Req{
			CommonMsg: deviceMsg.CommonMsg{
				Method:    deviceMsg.Report,
				MsgToken:  devices.GenMsgToken(ctx, d.svcCtx.NodeID),
				Timestamp: time.Now().UnixMilli(),
				Sys:       &deviceMsg.SysConfig{NoAsk: true},
			},
			Params: map[string]any{},
		}
		eventReq := msgThing.Req{
			CommonMsg: deviceMsg.CommonMsg{
				Method:    deviceMsg.EventPost,
				MsgToken:  devices.GenMsgToken(ctx, d.svcCtx.NodeID),
				Timestamp: time.Now().UnixMilli(),
				Sys:       &deviceMsg.SysConfig{NoAsk: true},
			},
			Params: map[string]any{},
		}
		var payload []byte
		var Type string
		for _, v := range req {
			if _, ok := model.Event[v.Id]; ok {
				eventReq.Params[v.Id] = map[string]any{"value": v.Value}
				payload, _ = json.Marshal(eventReq)
				Type = msgThing.TypeEvent
			} else {
				if strings.HasPrefix(v.Id, "array") { //数组类型
					num := v.Id[len("array_") : len("array_")+2]
					id := v.Id[len("array_00_"):]
					v.Id = schema.GenArray(id, cast.ToInt(num))
				}
				propertyReq.Params[v.Id] = v.Value
				payload, _ = json.Marshal(propertyReq)
				Type = msgThing.TypeProperty
			}
		}
		err = d.svcCtx.Protocol.DevPubMsg(ctx, &devices.DevPublish{
			Topic:      topic,
			Timestamp:  time.Now().UnixMilli(),
			ProductID:  productID,
			DeviceName: topics[1],
			Handle:     devices.Thing,
			Type:       Type,
			Payload:    payload,
		})
		return err
	}
	return nil
}
